package top.szhome.develop.service.impl;

import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import top.szhome.develop.convert.DatasourceConverter;
import top.szhome.develop.dto.DatasourceDTO;
import top.szhome.develop.entity.Datasource;
import top.szhome.develop.entity.Model;
import top.szhome.develop.entity.Property;
import top.szhome.develop.mapper.DatasourceMapper;
import top.szhome.develop.service.DatasourceService;
import top.szhome.develop.service.ModelService;
import top.szhome.develop.service.PropertyService;
import top.szhome.develop.vo.DatasourceVO;
import top.szhome.framework.starter.db.support.SimpleServiceImpl;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
 * 数据源服务实现
 *
 * @author 唐加利
 * @date 2023/08/21
 **/
@RequiredArgsConstructor
@Service
@Slf4j
public class DatasourceServiceImpl extends SimpleServiceImpl<DatasourceMapper, DatasourceConverter, DatasourceDTO, Datasource, DatasourceVO> implements DatasourceService {

    private final ModelService modelService;

    private final PropertyService propertyService;

    /**
     * 同步数据源
     * @param ids
     */
    @Override
    public void sync(List<Long> ids) {
        ids.forEach(id -> {
            Datasource datasource = getById(id);
            ConfigBuilder configBuilder = getConfigBuilder(datasource);
            configBuilder.getTableInfoList().forEach(table -> syncModel(datasource, table));
        });
    }

    /**
     * 同步表模型
     * @param datasource
     * @param table
     */
    private void syncModel(Datasource datasource, TableInfo table) {
        // 保存表对应的数据模型
        Model model = new Model();
        model.setDatasourceId(datasource.getId());
        model.setTableName(table.getName());
        String prefix = datasource.getTablePrefix();
        model.setCode(table.getEntityName().substring(prefix.length() - 1));
        model.setTablePrefix(datasource.getTablePrefix());

        String comment = table.getComment();
        model.setComments(comment);

        comment = comment.length() > 64 ? comment.substring(0, 64) : comment;
        model.setName(comment);
        try {
            modelService.save(model);
        } catch (DuplicateKeyException e) {
            log.warn("表同步失败，表已存在， table={}", table.getName());
        }

        // 保存各个列对应的属性
        AtomicInteger sort = new AtomicInteger(1);
        List<Property> properties = table.getFields().stream().map(field -> {
            Property property = toProperty(model, field);
            property.setSort(sort.getAndIncrement());
            return property;
        }).collect(Collectors.toList());

        try {
            propertyService.saveBatch(properties);
        } catch (DuplicateKeyException e) {
            log.warn("属性保存失败，属性已经存在", e);
        }
    }

    /**
     * 表字段转模型属性
     * @param model
     * @param field
     * @return
     */
    private Property toProperty(Model model, TableField field) {
        Property property = new Property();
        TableField.MetaInfo meta = field.getMetaInfo();
        property.setDatasourceId(model.getDatasourceId());
        property.setModelId(model.getId());
        property.setColumnComment(meta.getRemarks());
        property.setColumnName(field.getColumnName());
        property.setFieldLabel(meta.getRemarks().substring(0, Math.min(64, meta.getRemarks().length())));
        property.setFieldName(field.getPropertyName());
        property.setColumnType(meta.getJdbcType().name());
        property.setFieldType(field.getPropertyType());
        property.setColumnLength(meta.getLength());
        property.setColumnScale(meta.getScale());
        property.setColumnDefaultValue(meta.getDefaultValue());
        return property;
    }

    /**
     * 构造配置构造器
     * @param datasource
     * @return
     */
    private ConfigBuilder getConfigBuilder(Datasource datasource) {
        final String url = datasource.getUrl();
        final String username = datasource.getUsername();
        final String password = datasource.getPassword();
        StrategyConfig strategy = new StrategyConfig.Builder().addTablePrefix("t_").build();
        DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder(url, username, password).build();
        ConfigBuilder configBuilder = new ConfigBuilder(null, dataSourceConfig, strategy, null, null, null);
        return configBuilder;
    }
}
